import axios from 'axios';
import * as cheerio from 'cheerio';
import { OilPrice } from '@/models/OilPrice';
import { OilPriceData, OilPriceStatistics } from '@/types/oilPrice';

export class OilPriceService {
  private static instance: OilPriceService;
  private isUpdating = false;
  private lastUpdateTime: Date | null = null;
  private readonly UPDATE_INTERVAL = 24 * 60 * 60 * 1000; // 24小时更新一次

  private constructor() {}

  public static getInstance(): OilPriceService {
    if (!OilPriceService.instance) {
      OilPriceService.instance = new OilPriceService();
    }
    return OilPriceService.instance;
  }

  /**
   * 获取油价数据
   */
  async getOilPrices(
    province?: string,
    latest: boolean = true
  ): Promise<OilPriceData[]> {
    try {
      // 检查是否需要更新数据
      if (this.shouldUpdate()) {
        await this.updateOilPrices();
      }

      // 构建查询条件
      const filter: any = {};
      if (province) {
        filter.province = { $regex: province, $options: 'i' };
      }

      if (latest) {
        // 获取每个省份的最新数据
        const pipeline: any[] = [
          { $match: filter },
          { $sort: { updateTime: -1 } },
          {
            $group: {
              _id: '$province',
              doc: { $first: '$$ROOT' },
            },
          },
          { $replaceRoot: { newRoot: '$doc' } },
          { $sort: { province: 1 } },
        ];

        const results = await OilPrice.aggregate(pipeline);
        return results.map(doc => this.mapDocumentToData(doc));
      } else {
        // 获取所有数据
        const results = await OilPrice.find(filter).sort({ updateTime: -1 });
        return results.map(doc => this.mapDocumentToData(doc));
      }
    } catch (error) {
      console.error('获取油价数据失败:', error);
      throw new Error('获取油价数据失败');
    }
  }

  /**
   * 更新油价数据
   */
  async updateOilPrices(force: boolean = false): Promise<number> {
    if (this.isUpdating && !force) {
      throw new Error('油价数据正在更新中，请稍后再试');
    }

    if (!this.shouldUpdate() && !force) {
      throw new Error('油价数据无需更新');
    }

    this.isUpdating = true;

    try {
      console.log('开始更新油价数据...');

      // 抓取东方财富网数据
      const oilPrices = await this.scrapeEastMoneyData();

      if (oilPrices.length === 0) {
        throw new Error('抓取到的油价数据为空');
      }

      // 保存到数据库
      const savedCount = await this.saveOilPrices(oilPrices);

      this.lastUpdateTime = new Date();
      console.log(`油价数据更新完成，共保存 ${savedCount} 条记录`);

      return savedCount;
    } catch (error) {
      console.error('更新油价数据失败:', error);
      throw error;
    } finally {
      this.isUpdating = false;
    }
  }

  /**
   * 抓取东方财富网油价数据
   */
  private async scrapeEastMoneyData(): Promise<OilPriceData[]> {
    const url = 'https://data.eastmoney.com/cjsj/yjtz/default.html';

    try {
      // 设置请求头，模拟真实浏览器
      const headers = {
        'User-Agent':
          'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
        Accept:
          'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'Accept-Encoding': 'gzip, deflate, br',
        Connection: 'keep-alive',
        'Upgrade-Insecure-Requests': '1',
        'Cache-Control': 'max-age=0',
        Referer: 'https://data.eastmoney.com/',
      };

      // 添加随机延迟，避免被反爬
      await this.randomDelay(1000, 3000);

      const response = await axios.get(url, {
        headers,
        timeout: 30000,
        validateStatus: status => status === 200,
      });

      const $ = cheerio.load(response.data);
      const oilPrices: OilPriceData[] = [];

      // 解析表格数据
      $('table tr').each((i, row) => {
        if (i === 0) return; // 跳过表头

        const cells = $(row).find('td');
        if (cells.length >= 5) {
          const province = $(cells[0]).text().trim();
          const price92Text = $(cells[1]).text().trim();
          const price95Text = $(cells[2]).text().trim();
          const price98Text = $(cells[3]).text().trim();
          const price0Text = $(cells[4]).text().trim();

          // 解析价格数据
          const price92 = this.parsePrice(price92Text);
          const price95 = this.parsePrice(price95Text);
          const price98 = this.parsePrice(price98Text);
          const price0 = this.parsePrice(price0Text);

          if (price92 > 0 && price95 > 0 && price98 > 0 && price0 > 0) {
            oilPrices.push({
              province,
              price92,
              price95,
              price98,
              price0,
              updateTime: new Date(),
              source: 'eastmoney',
            });
          }
        }
      });

      console.log(`抓取到 ${oilPrices.length} 条油价数据`);
      return oilPrices;
    } catch (error) {
      console.error('抓取东方财富网数据失败:', error);
      throw new Error('抓取油价数据失败');
    }
  }

  /**
   * 解析价格字符串
   */
  private parsePrice(priceText: string): number {
    if (!priceText) return 0;

    // 移除价格中的非数字字符，只保留数字和小数点
    const price = parseFloat(priceText.replace(/[^\d.]/g, ''));
    return isNaN(price) ? 0 : price;
  }

  /**
   * 保存油价数据到数据库
   */
  private async saveOilPrices(oilPrices: OilPriceData[]): Promise<number> {
    let savedCount = 0;

    for (const oilPrice of oilPrices) {
      try {
        // 检查是否已存在该省份的最新数据
        const existingPrice = await OilPrice.findOne({
          province: oilPrice.province,
          source: oilPrice.source,
        }).sort({ updateTime: -1 });

        if (existingPrice) {
          // 如果价格有变化，则更新
          if (this.hasPriceChanged(existingPrice, oilPrice)) {
            await OilPrice.create(oilPrice);
            savedCount++;
          }
        } else {
          // 如果不存在，则创建新记录
          await OilPrice.create(oilPrice);
          savedCount++;
        }
      } catch (error) {
        console.error(`保存油价数据失败 (${oilPrice.province}):`, error);
      }
    }

    return savedCount;
  }

  /**
   * 检查价格是否有变化
   */
  private hasPriceChanged(existing: any, newPrice: OilPriceData): boolean {
    return (
      existing.price92 !== newPrice.price92 ||
      existing.price95 !== newPrice.price95 ||
      existing.price98 !== newPrice.price98 ||
      existing.price0 !== newPrice.price0
    );
  }

  /**
   * 获取油价统计信息
   */
  async getOilPriceStatistics(): Promise<OilPriceStatistics> {
    try {
      const latestPrices = await this.getOilPrices(undefined, true);

      if (latestPrices.length === 0) {
        throw new Error('没有可用的油价数据');
      }

      // 计算全国平均价格
      const nationalAverage = {
        price92: this.calculateAverage(latestPrices.map(p => p.price92)),
        price95: this.calculateAverage(latestPrices.map(p => p.price95)),
        price98: this.calculateAverage(latestPrices.map(p => p.price98)),
        price0: this.calculateAverage(latestPrices.map(p => p.price0)),
      };

      // 找出最高价格地区
      const highestPrice = {
        province: latestPrices[0]?.province || '未知',
        price92: Math.max(...latestPrices.map(p => p.price92)),
        price95: Math.max(...latestPrices.map(p => p.price95)),
        price98: Math.max(...latestPrices.map(p => p.price98)),
        price0: Math.max(...latestPrices.map(p => p.price0)),
      };

      // 找出最低价格地区
      const lowestPrice = {
        province: latestPrices[0]?.province || '未知',
        price92: Math.min(...latestPrices.map(p => p.price92)),
        price95: Math.min(...latestPrices.map(p => p.price95)),
        price98: Math.min(...latestPrices.map(p => p.price98)),
        price0: Math.min(...latestPrices.map(p => p.price0)),
      };

      return {
        nationalAverage,
        highestPrice,
        lowestPrice,
        trend: { price92: 0, price95: 0, price98: 0, price0: 0 }, // 暂时设为0，后续可以计算趋势
      };
    } catch (error) {
      console.error('获取油价统计信息失败:', error);
      throw error;
    }
  }

  /**
   * 计算平均值
   */
  private calculateAverage(prices: number[]): number {
    if (prices.length === 0) return 0;
    const sum = prices.reduce((acc, price) => acc + price, 0);
    return Math.round((sum / prices.length) * 100) / 100;
  }

  /**
   * 检查是否需要更新数据
   */
  private shouldUpdate(): boolean {
    if (!this.lastUpdateTime) return true;

    const now = new Date();
    const timeDiff = now.getTime() - this.lastUpdateTime.getTime();

    return timeDiff >= this.UPDATE_INTERVAL;
  }

  /**
   * 随机延迟
   */
  private async randomDelay(min: number, max: number): Promise<void> {
    const delay = Math.random() * (max - min) + min;
    return new Promise(resolve => setTimeout(resolve, delay));
  }

  /**
   * 将数据库文档映射为数据类型
   */
  private mapDocumentToData(doc: any): OilPriceData {
    return {
      province: doc.province,
      price92: doc.price92,
      price95: doc.price95,
      price98: doc.price98,
      price0: doc.price0,
      updateTime: doc.updateTime,
      source: doc.source,
    };
  }

  /**
   * 获取最后更新时间
   */
  getLastUpdateTime(): Date | null {
    return this.lastUpdateTime;
  }

  /**
   * 获取更新状态
   */
  getUpdateStatus(): boolean {
    return this.isUpdating;
  }
}
